home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / dialupip / dialupip2.0 / src / diald / makecall.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-01-11  |  14.6 KB  |  560 lines

  1. /*
  2. **  Copyright (c) 1991 Bolt Beranek and Newman, Inc.
  3. **  All rights reserved.
  4. **
  5. **  Redistribution and use in source and binary forms are permitted
  6. **  provided that: (1) source distributions retain this entire copyright
  7. **  notice and comment, and (2) distributions including binaries display
  8. **  the following acknowledgement:  ``This product includes software
  9. **  developed by Bolt Beranek and Newman, Inc. and CREN/CSNET'' in the
  10. **  documentation or other materials provided with the distribution and in
  11. **  all advertising materials mentioning features or use of this software.
  12. **  Neither the name of Bolt Beranek and Newman nor CREN/CSNET may be used
  13. **  to endorse or promote products derived from this software without
  14. **  specific prior written permission.
  15. **
  16. **  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17. **  WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18. **  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19. */
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #include <errno.h>
  23. #include <fcntl.h>
  24. #include <netdb.h>
  25. #include <setjmp.h>
  26. #include <sgtty.h>
  27. #include <signal.h>
  28. #include <sys/types.h>
  29. #include <sys/param.h>
  30. #include <sys/ioctl.h>
  31. #include <sys/socket.h>
  32. #include <netinet/in.h>
  33. #include <netinet/in_systm.h>
  34. #include <netinet/ip.h>
  35. #include <net/if.h>
  36. #include <net/if_du.h>
  37. #include "diald.h"
  38. #include "dialupip.h"
  39.  
  40. #ifdef    sun
  41. #define GETDATAVAL(ifr)        (*(int *)ifr.ifr_data)
  42. #define SETDATAVAL(ifr, i)    (*(int *)(ifr).ifr_data = (i))
  43. #else
  44. #define GETDATAVAL(ifr)        ((int)ifr.ifr_data)
  45. #define SETDATAVAL(ifr, i)    ((ifr).ifr_data = (caddr_t)(i))
  46. #endif    /* sun */
  47.  
  48. /*
  49. ** Local Variables
  50. */
  51. static char    device[12];    /* Device name                */
  52. static char    tty[12];    /* Modem in use                */
  53. static int    mypid;
  54. static int    dialfout;    /* Modem descriptor            */
  55. static long    startipkts;    /* Starting input packet count        */
  56. static long    startopkts;    /* Starting output packet count        */
  57. static struct ifreq ifr;
  58. static int    oldinactive;    /* Old inactivity value            */
  59. static struct sgttyb oldsgtty;    /* Old TTY modes            */
  60. static jmp_buf    opentimeout;    /* Used for open timeouts        */
  61. static int    sock;        /* The global socket for use everywhere    */
  62. static time_t    starttime;    /* Time call started            */
  63. static time_t    stoptime;    /* Time call stopped            */
  64. static long    duration;    /* Duration of call in seconds        */
  65. static char    sitename[30];    /* Name of site called            */
  66.  
  67.  
  68. extern char    *strerror();
  69.  
  70.  
  71.  
  72. /*
  73. **  Log that a call failed.
  74. */
  75. void
  76. failcall(devname, mesg)
  77.     char        *devname;
  78.     char        *mesg;
  79. {
  80.     static char        WHERE[] = "failcall";
  81.     int            s;
  82.     struct ifreq    ifr;
  83.  
  84.     if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  85.     d_log(DLOG_GENERAL, WHERE, "Can't create socket for \"%s\", %m",
  86.         devname);
  87.     d_log(DLOG_GENERAL, WHERE, "%s", mesg);
  88.     return;
  89.     }
  90.  
  91.     (void)strcpy(ifr.ifr_name, devname);
  92.     if (ioctl(s, SIOCFAILCALL, (caddr_t)&ifr) < 0) {
  93.     d_log(DLOG_GENERAL, WHERE, "Can't SIOCFAILCALL on \"%s\", %m",
  94.         devname);
  95.     d_log(DLOG_GENERAL, WHERE, "%s", mesg);
  96.     return;
  97.     }
  98.  
  99.     d_log(DLOG_ALL, WHERE, "Did SIOCFAILCALL on \"%s\"", devname);
  100.     d_log(DLOG_ALL, WHERE, "%s", mesg);
  101. }
  102.  
  103.  
  104. /*
  105. **  Get the packet counts from the interface.
  106. */
  107. static void
  108. getpacketcounts(ipkts, opkts)
  109.     long    *ipkts;
  110.     long    *opkts;
  111. {
  112.     static char    WHERE[] = "getpacketcounts";
  113.  
  114.     /* Zero out the counts */
  115.     *ipkts = *opkts = 0;
  116.  
  117.     if (ioctl(sock, SIOCGIPKTS, (caddr_t)&ifr) < 0) {
  118.     d_log(DLOG_GENERAL, WHERE, "Can't SIOCGIPKTS for \"%s\", %m", device);
  119.     unlock_pid();
  120.     exit(1);
  121.     }
  122.     *ipkts = (long)GETDATAVAL(ifr);
  123.  
  124.     if (ioctl(sock, SIOCGOPKTS, (caddr_t)&ifr) < 0) {
  125.     d_log(DLOG_GENERAL, WHERE, "Can't SIOCGOPKTS for \"%s\", %m", device);
  126.     unlock_pid();
  127.     exit(1);
  128.     }
  129.     *opkts = (long)GETDATAVAL(ifr);
  130. }
  131.  
  132.  
  133. static int
  134. set_inactivity(max_inactivity)
  135.     int        max_inactivity;
  136. {
  137.     static char    WHERE[] = "set_inactivity";
  138.     int        old;
  139.  
  140.     /* Get the old value */
  141.     if (ioctl(sock, SIOCGATIMEO, (caddr_t)&ifr) < 0) {
  142.     d_log(DLOG_GENERAL, WHERE, "Can't SIOCGATIMEO for \"%s\", %m", device);
  143.     old = -1;
  144.     }
  145.     else
  146.     old = GETDATAVAL(ifr);
  147.  
  148.     /* If the new time is negative, then just return the current value */
  149.     if (max_inactivity < 0) {
  150.     d_log(DLOG_DIAG, WHERE, "Timeout for \"%s\" unchanged from %d",
  151.         device, old);
  152.     return old;
  153.     }
  154.  
  155.     /* Set the inactivity timer */
  156.     SETDATAVAL(ifr, max_inactivity);
  157.     if (ioctl(sock, SIOCSATIMEO, (caddr_t)&ifr) < 0)
  158.     d_log(DLOG_GENERAL, WHERE, "Can't SIOCSATIMEO for \"%s\", %m", device);
  159.     else if (max_inactivity)
  160.     d_log(DLOG_INFO, WHERE, "Timeout for \"%s\" set to %d",
  161.         device, max_inactivity);
  162.     else
  163.     d_log(DLOG_INFO, WHERE,
  164.          "Timeout for \"%s\" disabled; must be brought down manually",
  165.          device);
  166.  
  167.     return old;
  168. }
  169.  
  170.  
  171. static void
  172. writelog()
  173. {
  174.     static char    WHERE[] = "writelog";
  175.     FILE    *F;
  176.     long    hours;
  177.     long    minutes;
  178.     long    seconds;
  179.  
  180.     /* Just in case... */
  181.     if (starttime == 0)
  182.     return;
  183.  
  184.     if ((F = fopen(CALL_LOG, "a")) == NULL) {
  185.     d_log(DLOG_DIAG, WHERE, "Can't open call log, %m");
  186.     return;
  187.     }
  188.  
  189.     hours = duration / 3600;
  190.     minutes = (duration - hours * 3600) / 60;
  191.     seconds = duration - hours * 3600 - minutes * 60;
  192.  
  193.     (void)fprintf(F, "%-16.16s  %-19.19s  %02ld:%02ld:%02ld   %s\n",
  194.     sitename, ctime(&stoptime), hours, minutes, seconds, progname);
  195.     (void)fclose(F);
  196. }
  197.  
  198.  
  199. /*
  200. **  Catch signal and exit.
  201. */
  202. static void
  203. hangup(sig)
  204.     int            sig;
  205. {
  206.     static char    WHERE[] = "hangup";
  207.     long        totalpkts;
  208.     long        endipkts;
  209.     long        endopkts;
  210.     int            disc;
  211.     int            status;
  212.  
  213.     /* Now ignore the signals since we're shutting down. */
  214.     (void)signal(SIGHUP, SIG_IGN);
  215.     (void)signal(SIGTERM, SIG_IGN);
  216.     d_log(DLOG_ALL, WHERE, "Process %d got signal %d for \"%s\"",
  217.     mypid, sig, device);
  218.  
  219.     /* Let go of the lock file */
  220.     (void)uu_unlock(tty);
  221.     unlock_pid();
  222.  
  223.     /* Log the statistics */
  224.     (void)time(&stoptime);
  225.     duration = stoptime - starttime;
  226.     writelog();
  227.  
  228.     getpacketcounts(&endipkts, &endopkts);
  229.     totalpkts = (endipkts - startipkts) + (endopkts - startopkts);
  230.     d_log(DLOG_INFO, WHERE, "Outbound interface \"%s\" up %ld seconds",
  231.     device, duration);
  232.     d_log(DLOG_DIAG, WHERE,
  233.     "Inpackets = %ld, Outpackets = %ld, Average = %.2f packets/sec",
  234.     endipkts - startipkts, endopkts - startopkts,
  235.     totalpkts ? ((float)totalpkts) / ((float)duration) : 0);
  236.  
  237.     /* Restore the inactivity counter, disconnect and exit */
  238.     (void)set_inactivity(oldinactive);
  239.  
  240.     status = 0;
  241.  
  242.     /* Bring back the line discipline. */
  243.     disc = NTTYDISC;
  244.     if (ioctl(dialfout, TIOCSETD, (caddr_t)&disc) < 0) {
  245.     d_log(DLOG_GENERAL, WHERE, "Can't TIOCSETD \"%s\", %m", device);
  246.     status = 1;
  247.     }
  248.  
  249.     /* Reset the TTY modes. */
  250.     if (ioctl(dialfout, TIOCSETP, (caddr_t)&oldsgtty) < 0) {
  251.     d_log(DLOG_GENERAL, WHERE, "Can't TIOCSETP \"%s\", %m", device);
  252.     status = 1;
  253.     }
  254.  
  255.     /* Drop DTR. */
  256.     if (ioctl(dialfout, TIOCCDTR, (caddr_t)0) < 0) {
  257.     d_log(DLOG_GENERAL, WHERE, "Can't TIOCCDTR \"%s\", %m", device);
  258.     status = 1;
  259.     }
  260.  
  261.     /* All done, report that we made it. */
  262.     d_log(DLOG_GENERAL, WHERE, "Disconnected \"%s\"", device);
  263.     exit(status);
  264. }
  265.  
  266.  
  267. /*
  268. **  Set line to have the right discipline and modes.
  269. */
  270. static int
  271. duconnect(device)
  272.     char        *device;
  273. {
  274.     static char        WHERE[] = "duconnect";
  275.     int            dudisc;
  276.     struct ifreq    ifr;
  277.     struct sgttyb    sgtty;
  278.     char        *p;
  279.     int            uid;
  280.  
  281.     /* Get the current modes. */
  282.     if (ioctl(dialfout, TIOCGETP, (caddr_t)&sgtty) < 0) {
  283.     d_log(DLOG_GENERAL, WHERE, "Can't TIOCGETP on \"%s\", %m", device);
  284.     return CALL_IOCTL_ERR;
  285.     }
  286.     oldsgtty = sgtty;
  287.  
  288.     /* Set the new modes. */
  289.     sgtty.sg_flags = RAW | ANYP;
  290.     if (ioctl(dialfout, TIOCSETP, (caddr_t)&sgtty) < 0) {
  291.     d_log(DLOG_GENERAL, WHERE, "Can't TIOCSETP on \"%s\", %m", device);
  292.     return CALL_IOCTL_ERR;
  293.     }
  294.  
  295.     /* Find the device number and convert */
  296.     /* NEED TO BE MORE INTELLIGENT ABOUT THIS */
  297.     (void)strcpy(ifr.ifr_name, device);
  298.     for (p = device; *p && !isdigit(*p); p++)
  299.     ;
  300.  
  301. #ifdef    ifr_metric
  302.     if (*p == '\0') {
  303.     d_log(DLOG_GENERAL, WHERE, "Can't find unit number in \"%s\"", device);
  304.     return CALL_BAD_IF;
  305.     }
  306.     ifr.ifr_metric = atoi(p);
  307. #endif
  308.  
  309.     /* Become root. */
  310.     uid = getuid();
  311.     if (setuid(0) < 0) {
  312.     d_log(DLOG_GENERAL, WHERE, "Can't setuid to root, %m");
  313.     return CALL_NOSETUID;
  314.     }
  315.  
  316.     /* Change to the DIP discipline. */
  317.     dudisc = DUDISC;
  318.     if (ioctl(dialfout, TIOCSETD, (caddr_t)&dudisc) < 0) {
  319.     d_log(DLOG_GENERAL, WHERE,
  320.         "Can't TIOCSETD on \"%s\", %m -- is DIP configured?",
  321.         device);
  322.     return CALL_IOCTL_ERR;
  323.     }
  324.  
  325.     if (ioctl(dialfout, SIOCSIFADDR, (caddr_t)&ifr) < 0) {
  326.     d_log(DLOG_GENERAL, WHERE,
  327.         "Can't SIOCSIFADDR on \"%s\", %m --  is device installed?",
  328.         device);
  329.     return CALL_IOCTL_ERR;
  330.     }
  331.  
  332.     d_log(DLOG_ALL, WHERE, "Did SIOCISFADDR on \"%s\"",device);
  333.     (void)setuid(uid);
  334.     return CALL_SUCCESS;
  335. }
  336.  
  337.  
  338. /*
  339. **  Get a modem from the list of usable ones for this system and return
  340. **  the first one that isn't already in use.  NOTE:  We must respect locks
  341. **  made by uucp, tip, cmdf et al
  342. */
  343. static int
  344. find_modem(rp)
  345.     REMOTE        *rp;
  346. {
  347.     register int    i;
  348.  
  349.     for (i = 0; i < MAXDEVICES && rp->Lines[i][0]; i++)
  350.     if (uu_lock(rp->Lines[i]) >= 0)
  351.         return i;
  352.     return -1;
  353. }
  354.  
  355.  
  356. /*
  357. **  Catch an alarm while waiting for the open to succeed.
  358. */
  359. static void
  360. open_timeout()
  361. {
  362.     longjmp(opentimeout, 1);
  363.     /* NOTREACHED */
  364. }
  365.  
  366.  
  367. static int
  368. makecall_real(rp)
  369.     REMOTE        *rp;
  370. {
  371.     static char        WHERE[] = "makecall";
  372.     char        devtty[30];
  373.     FILE        *fp;
  374.     char        logbuf[256];
  375.     struct sgttyb    sgtty;
  376.     int            stat;
  377.     char        *tname;
  378.     int            i;
  379.  
  380.     /* Open our own path to the terminal and close the old connections */
  381.     if ((i = open("/dev/tty", O_RDONLY)) >= 0) {
  382.     (void)ioctl(i, TIOCNOTTY, (caddr_t)0);
  383.     (void)close(i);
  384.     }
  385.     (void)fclose(stdin);
  386.     (void)fclose(stdout);
  387.  
  388.     /* Find a modem. */
  389.     if ((i = find_modem(rp)) < 0) {
  390.     (void)sprintf(logbuf,
  391.         "Can't find modem for \"%s\" -- check lock files.",
  392.         rp->Sitename);
  393.     failcall(rp->Device, logbuf);
  394.     return CALL_PERMISSION;
  395.     }
  396.     (void)strcpy(tty, rp->Lines[i]);
  397.     (void)strcpy(sitename, rp->Sitename);
  398.     (void)strcpy(device, rp->Device);
  399.  
  400.     /* Set up exit handler. */
  401.     (void)signal(SIGHUP, hangup);
  402.     (void)signal(SIGTERM, hangup);
  403.  
  404.     /* Set up a time-out handler.  Main reason for the open timing-out is
  405.      * because modem is off, or not configured correctly. */
  406.     (void)sprintf(devtty, "/dev/%s", tty);
  407.     (void)signal(SIGALRM, open_timeout);
  408.     if (setjmp(opentimeout)) {
  409.     /* Open failed. */
  410.     (void)sprintf(logbuf, "Time-out opening modem \"%s\" for \"%s\"",
  411.         devtty, rp->Sitename);
  412.     failcall(rp->Device, logbuf);
  413.     (void)uu_unlock(tty);
  414.     return CALL_TTYTIMEOUT;
  415.     }
  416.  
  417.     /* Open the modem port */
  418.     (void)alarm(OPEN_TIMEOUT);
  419.     if ((dialfout = open(devtty, O_RDWR)) < 0) {
  420.     (void)sprintf(logbuf, "Can't open modem \"%s\" for \"%s\", %s",
  421.         devtty, rp->Sitename, strerror(errno));
  422.     failcall(rp->Device, logbuf);
  423.     (void)uu_unlock(tty);
  424.     return CALL_PERMISSION;
  425.     }
  426.  
  427.     /* Turn off the timeout, record what we're using. */
  428.     (void)alarm(0);
  429.     (void)signal(SIGALRM, SIG_DFL);
  430.     (void)record_pid(rp->Device);
  431.  
  432.     /* Get the TTY modes. */
  433.     if (ioctl(dialfout, TIOCGETP, (caddr_t)&sgtty) < 0) {
  434.     (void)sprintf(logbuf, "Can't TIOCGETP for \"%s\", %s",
  435.         rp->Sitename, strerror(errno));
  436.     failcall(rp->Device, logbuf);
  437.     (void)uu_unlock(tty);
  438.     return CALL_IOCTL_ERR;
  439.     }
  440.  
  441.     /* Set the new bits. */
  442.     if (rp->Speeds[i] > 0)
  443.     sgtty.sg_ispeed = sgtty.sg_ospeed = rp->Speeds[i];
  444.     sgtty.sg_flags |= CBREAK;
  445.     sgtty.sg_flags &= ~ECHO;
  446.  
  447.     /* Set the new mode. */
  448.     if (ioctl(dialfout, TIOCSETP, (caddr_t)&sgtty) < 0) {
  449.     (void)sprintf(logbuf, "Can't TIOCSETP for \"%s\", %s",
  450.         rp->Sitename, strerror(errno));
  451.     failcall(rp->Device, logbuf);
  452.     (void)uu_unlock(tty);
  453.     return CALL_IOCTL_ERR;
  454.     }
  455.  
  456.     /* Change process group, set hangup on close. */
  457.     if (ioctl(dialfout, TIOCHPCL, (caddr_t)&sgtty) < 0) {
  458.     (void)sprintf(logbuf, "Can't TIOCHPCL for \"%s\", %s",
  459.         rp->Sitename, strerror(errno));
  460.     failcall(rp->Device, logbuf);
  461.     (void)uu_unlock(tty);
  462.     return CALL_IOCTL_ERR;
  463.     }
  464.  
  465.     /* Open up the modem port. */
  466.     if ((fp = fdopen(dialfout, "r+")) == NULL) {
  467.     (void)sprintf(logbuf, "Can't fdopen modem port for \"%s\"",
  468.         rp->Sitename);
  469.     failcall(rp->Device, logbuf);
  470.     (void)uu_unlock(tty);
  471.     return CALL_PERMISSION;
  472.     }
  473.  
  474.     /* Set up the name of the transaction file. */
  475.     tname = rp->Transcript[0] ? rp->Transcript : NULL;
  476.  
  477.     /* Now run the script. */
  478.     d_log(DLOG_GENERAL, WHERE, "Attempting connection to \"%s\" via \"%s\"",
  479.     rp->Sitename, rp->Device);
  480.     if (runscript(rp, fp, tname) < 0) {
  481.     (void)sprintf(logbuf, "Script \"%s\" for \"%s\" failed",
  482.         rp->Script, rp->Sitename);
  483.     failcall(rp->Device, logbuf);
  484.     (void)uu_unlock(tty);
  485.     return CALL_FAIL;
  486.     }
  487.  
  488.     /* Connection set up, set the line discipline. */
  489.     if ((stat = duconnect(rp->Device)) != CALL_SUCCESS) {
  490.     (void)uu_unlock(tty);
  491.     return stat;
  492.     }
  493.  
  494.     /* Connection made - get things going */
  495.     d_log(DLOG_GENERAL, WHERE, "Connected to \"%s\" via \"%s\"",
  496.     sitename, device);
  497.     return CALL_SUCCESS;
  498. }
  499.  
  500. int
  501. makecall(rp)
  502.     REMOTE        *rp;
  503. {
  504.     static char        WHERE[] = "makecall";
  505.     int            uptime;
  506.     int            old_if;
  507.     int            old_soft;
  508.  
  509.     /* Record the PID */
  510.     mypid = getpid();
  511.  
  512.     if (makecall_real(rp) != CALL_SUCCESS)
  513.     return;
  514.  
  515.     /* Create a socket for gathering info. */
  516.     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  517.     d_log(DLOG_GENERAL, WHERE, "Can't create socket for \"%s\", %m",
  518.         device);
  519.     unlock_pid();
  520.     exit(1);
  521.     }
  522.  
  523.     /* Set up info, collect starting stats. */
  524.     (void)strcpy(ifr.ifr_name, device);
  525.     oldinactive = set_inactivity(rp->Inactivity);
  526.     (void)time(&starttime);
  527.     getpacketcounts(&startipkts, &startopkts);
  528.     d_log(DLOG_DIAG, WHERE,
  529.     "Outbound interface \"%s\" starting ipkts = %ld, opkts = %ld",
  530.     device, startipkts, startopkts);
  531.  
  532.     /* Now keep tabs on the interface */
  533.     for (old_if = old_soft = 0, uptime = 0; ; ) {
  534.     /* See if the IF flags changed. */
  535.     if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
  536.         d_log(DLOG_GENERAL, WHERE, "Can't SIOCGIFFLAGS, %m");
  537.     else if (ifr.ifr_flags != old_if) {
  538.         d_log(DLOG_ALL, WHERE,
  539.         "\"%s\" IF flags changed from 0x%04x to 0x%04x",
  540.         device, old_if, ifr.ifr_flags);
  541.         old_if = ifr.ifr_flags;
  542.     }
  543.  
  544.     /* See if the soft flags changed. */
  545.     if (ioctl(sock, SIOCGSOFTFLAGS, (caddr_t)&ifr) < 0)
  546.         d_log(DLOG_GENERAL, WHERE, "Can't SIOCGSOFTFLAGS, %m");
  547.     else if (GETDATAVAL(ifr) != old_soft) {
  548.         d_log(DLOG_ALL, WHERE,
  549.         "\"%s\" SOFT flags changed from 0x%04x to 0x%04x",
  550.         device, old_soft, GETDATAVAL(ifr));
  551.         old_soft = GETDATAVAL(ifr);
  552.     }
  553.  
  554.     (void)sleep(UPTIME_INTERVAL * 60);
  555.     uptime += UPTIME_INTERVAL;
  556.     d_log(DLOG_INFO, WHERE, "Outbound interface \"%s\" up %d minutes",
  557.         device, uptime);
  558.     }
  559. }
  560.